#  This file is part of OpenLightingDesigner.
# 
#  OpenLightingDesigner is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#
#  OpenLightingDesigner is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with OpenLightingDesigner.  If not, see <http://www.gnu.org/licenses/>.
#
# DeviceGroup.py
# Copyright (c) 2010 - 2011 Matthew Reid

from Group import GroupBase
from AttributeGroup import groupClasses, ParameterGroup

class DeviceGroup(GroupBase):
    _saved_class_name = 'DeviceGroup'
    _saved_attributes = ['group_keys', 'submaster']
    _saved_child_objects = ['AttributeGroups']
    signals_to_register = ['new_parameter_group', 'member_obj_request', 'index_changed']
    _Properties = {'submaster':dict(default=False), 
                   'ActivePalettes':dict(default={}, quiet=True)}
    _SettingsProperties = ['submaster']
    def __init__(self, **kwargs):
        self.ParameterGroups = {}
        self.ActivePaletteData = {}
        self.palette_added_by_osc = False
        self.palette_del_by_osc = False
        self.MainController = kwargs.get('MainController')
        kwargs['root_category'] = self.MainController.DeviceSystem.root_category.subcategories['device']
        super(DeviceGroup, self).__init__(**kwargs)
        if None in self.member_order.keys():
            bob
            self.member_order.del_child(self.member_order[None])
        if 'deserialize' not in kwargs:
            if self.name == self.__class__.__name__:
                self.name = 'Group%s' % (self.Index)
            self.submaster = kwargs.get('submaster', False)
            self.AttributeGroups = {}
            #self.member_groups = {}
            self.group_keys = {}
            for key, val in groupClasses.iteritems():
                g_kwargs = self.add_osc_child(address=key)
                g_kwargs.update({'parent_group':self, 'id':'_'.join([self.id, key]), 
                                 'root_category':self.root_category.parent.subcategories['attribute'], 
                                 'submaster':self.submaster})
                group = val(**g_kwargs)
                self.AttributeGroups.update({key:group})
        if not hasattr(self, 'group_keys') or self.group_keys is None:
            self.group_keys = {}
        self.members_changed_by_osc = False
        if self.osc_enabled:
            self.add_osc_handler(callbacks={'add-member':self.on_osc_add_member, 
                                            'del-member':self.on_osc_del_member, 
                                            'add-palette':self.on_osc_add_palette, 
                                            'del-palette':self.on_osc_del_palette, 
                                            'get-palettes':self.on_osc_request_palettes})
        devices = kwargs.get('devices', [])
        self.add_devices(devices, initializing=True)
        
        self.request_member_obj()
        self.bind(Index=self._on_Index_set, 
                  ActivePalettes=self._on_ActivePalettes_changed)
                  
    def _on_ActivePalettes_changed(self, **kwargs):
        old = kwargs.get('old')
        value = kwargs.get('value')
        
        
    def _on_Index_set(self, **kwargs):
        value = kwargs.get('value')
        old = kwargs.get('old')
        if self.name == 'Group%s' % (old):
            self.name = 'Group%s' % (value)
        
    def clean_members(self):
        for group in self.AttributeGroups.itervalues():
            group.clean_member_values()
        for group in self.ParameterGroups.itervalues():
            group.clean_member_values()
        keys = set()
        for key in self.group_keys.iterkeys():
            if key not in self.members:
                keys.add(key)
        for key in keys:
            del self.group_keys[key]
        
    def add_devices(self, devices, initializing=False):
        if not self.membership_lock:
            if type(devices) == list or type(devices) == tuple:
                for device in devices:
                    if initializing:
                        self.members_changed_by_osc = True
                    self.add_member(**{device.id:device})
            else:
                if initializing:
                    self.members_changed_by_osc = True
                self.add_member(**{devices.id:devices})
            
    def add_member(self, **kwargs):
        super(DeviceGroup, self).add_member(**kwargs)
        if not self.membership_lock:
            for key, val in kwargs.iteritems():
                self.group_keys.update({key:{}})
                #self.update_member_groups(key)
                member = self.members[key]
                if isinstance(val, GroupBase):
                    attrib_groups = member.AttributeGroups
                else:
                    attrib_groups = self.members[key].Groups
                for grkey, grval in attrib_groups.iteritems():
                    self.group_keys[key].update({grkey:grval.id})
                    self.AttributeGroups[grkey].add_member(**{grval.id:grval})
                for grkey, grval in val.ParameterGroups.iteritems():
                    if grval.name not in self.ParameterGroups:
                        group = ParameterGroup(attribute_name=grval.attribute_name, 
                                               parent_group=self, osc_parent_node=self.osc_node, 
                                               root_category=self.root_category.parent.subcategories['attribute'])
                        self.ParameterGroups.update({grval.name:group})
                        #print 'added param group ', group.name
                        self.group_keys[key].update({grkey:grval.id})
                        self.emit('new_parameter_group', device_group=self, param_group=group)
                    self.ParameterGroups[grval.name].add_member(**{grval.id:grval})
                #if len(self.members) > 1:
                #    bob
                if not self.members_changed_by_osc:
                    self.osc_node.send_message(address='add-member', value=key)
            self.members_changed_by_osc = False
            
    def del_member(self, key):
        if key in self.members and not self.membership_lock:
            for grkey, grval in self.AttributeGroups.iteritems():
                group_name = self.group_keys[key].get(grkey)
                if group_name:
                    grval.del_member(group_name)
            for grkey, grval in self.ParameterGroups.iteritems():
                if grkey in self.members[key].ParameterGroups:
                    grval.del_member(self.members[key].ParameterGroups[grkey].id)
            del self.group_keys[key]
            if not self.members_changed_by_osc:
                self.osc_node.send_message(address='del-member', value=key)
        super(DeviceGroup, self).del_member(key)
        self.members_changed_by_osc = False
        
    def apply_CategoryPalette(self, **kwargs):
        category = kwargs.get('category')
        index = kwargs.get('index')
        cpalette = self.MainController.EffectsSystem.CategoryPalettes[category][index]
        cpalette.set_groups(group=self)
        
    def add_active_palette(self, **kwargs):
        palette = kwargs.get('palette')
        category_palette = kwargs.get('category_palette')
        groups = kwargs.get('groups')
        is_parent = kwargs.get('is_parent')
        category = category_palette.category.name
        self.del_active_palette(category=category, set_to_none=False)
        self.ActivePaletteData[category] = {'palette':palette, 
                                            'category_palette':category_palette, 
                                            'groups':groups, 
                                            'is_parent':is_parent}
        self.ActivePalettes[category] = category_palette.Index
        if is_parent and not self.palette_added_by_osc:
            osckwargs = dict(address='add-palette', value=[category, category_palette.Index])
            #if not self.osc_node.oscMaster:
            #    osckwargs['to_master'] = True
            self.osc_node.send_message(**osckwargs)
        
    def del_active_palette(self, **kwargs):
        category = kwargs.get('category')
        set_to_none = kwargs.get('set_to_none', True)
        if not category:
            palette = kwargs.get('palette')
            category = palette.category.name
        d = self.ActivePaletteData.get(category)
        if d is not None and category in self.ActivePaletteData:
            if d['palette']:
                d['category_palette'].EffectsSystem.clear_palette(id=d['palette'].id)
            if d['groups']:
                for key in d['groups'].keys()[:]:
                    group = d['groups'][key]
                    group.unlink()
                    if len(group.members):
                        bob
                    del d['groups'][key]
                #d['groups'].clear()
            for m in self.members.itervalues():
                if m.ActivePalettes.get(category) == self.ActivePalettes[category]:
                    m.del_active_palette(category=category, set_to_none=set_to_none)
            del self.ActivePaletteData[category]
            if set_to_none:
                self.ActivePalettes[category] = None
            if d.get('is_parent') and not self.palette_del_by_osc:
                osckwargs = dict(address='del-palette', value=category)
                #if not self.osc_node.oscMaster:
                #    osckwargs['to_master'] = True
                self.osc_node.send_message(**osckwargs)
    
    def find_ActivePalette_parent(self, **kwargs):
        category = kwargs.get('category')
        if self.ActivePalettes.get(category) is None:
            return False
        if self.ActivePaletteData[category]['is_parent']:
            return self
        return False
    
    def on_osc_add_palette(self, **kwargs):
        category, index = kwargs.get('values')
        self.palette_added_by_osc = True
        self.apply_CategoryPalette(category=category, index=index)
        self.palette_added_by_osc = False
        
    def on_osc_del_palette(self, **kwargs):
        category = kwargs.get('values')[0]
        self.palette_del_by_osc = True
        self.del_active_palette(category=category)
        self.palette_del_by_osc = False
        
    def on_osc_request_palettes(self, **kwargs):
        client = kwargs.get('client')
        for key, val in self.ActivePaletteData.iteritems():
            if not val['is_parent']:
                continue
            cp = val['category_palette']
            self.osc_node.send_message(address='add-palette', 
                                       value=[cp.category.name, cp.Index], 
                                       client=client)
            
    def request_member_obj(self):
        for key in self.group_keys.iterkeys():
            if key not in self.members:
                self.MainController.on_group_member_obj_request(id=key, group=self)
                #self.emit('member_obj_request', id=key, group=self)
                
    def on_osc_add_member(self, **kwargs):
        values = kwargs.get('values')
        self.members_changed_by_osc = True
        self.MainController.on_group_member_obj_request(id=values[0], group=self)
        #self.emit('member_obj_request', id=values[0], group=self)
        
    def on_osc_del_member(self, **kwargs):
        values = kwargs.get('values')
        self.members_changed_by_osc = True
        self.del_member(values[0])
        
    def request_values_from_osc(self, **kwargs):
        for a in self.AttributeGroups.itervalues():
            a.request_values_from_osc(**kwargs)
        nkwargs = kwargs.copy()
        nkwargs['address'] = 'get-palettes'
        self.osc_node.send_message(**nkwargs)
        
    def get_values(self):
        d = {}
        for key, val in self.AttributeGroups.iteritems():
            d.update({key:val.get_values()})
        return d
        
    def get_devices(self):
        d = {}
        for key, val in self.members.iteritems():
            if getattr(val, 'base_class') == 'PatchedDevice':
                d.update({key:val})
            elif getattr(val, 'base_class') == 'Group':
                d.update(val.get_devices())
        return d
        
    def get_objects(self, **kwargs):
        d = kwargs.get('obj_dict', {})
        captured_only = kwargs.get('captured_only', False)
        for key in ['DeviceGroup', 'AttributeGroup', 'ParameterGroup', 'Device', 'Attribute']:
            if key not in d:
                d.update({key:{}})
        d['DeviceGroup'].update({self.id:self})
        if 'obj_dict' not in kwargs:
            kwargs['obj_dict'] = d
        for group in self.AttributeGroups.itervalues():
            group.get_objects(**kwargs)
        for group in self.ParameterGroups.itervalues():
            group.get_objects(**kwargs)
        for key, val in self.members.iteritems():
            if val.saved_class_name == 'PatchedDevice':
                d['Device'].update({key:val})
        return d
        
    def search_for_obj(self, objkey):
        if objkey in self.AttributeGroups:
                return self.AttributeGroups[objkey]
        for group in self.AttributeGroups.itervalues():
            result = group.search_for_obj(objkey)
            if result:
                return result
        return super(DeviceGroup, self).search_for_obj(objkey)
            
    def _deserialize_child(self, d, **kwargs):
        for cls in groupClasses.itervalues():
            if cls._saved_class_name == d['saved_class_name']:
                g_kwargs = self.add_osc_child(address=d['saved_class_name'])
                g_kwargs.update({'parent_group':self, 'deserialize':d, 'submaster':self.submaster, 
                                 'root_category':self.root_category.parent.subcategories['attribute']})
                return cls(**g_kwargs)
        return super(DeviceGroup, self)._deserialize_child(d, **kwargs)
        
